package sifeap.pl.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import javax.faces.application.FacesMessage;
import javax.faces.application.NavigationHandler;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;

import sifeap.exception.SifeapException;

/**
 * Utilidades para JSF
 */
public final class FacesUtils {

	private static final String ESPACIO_BLANCO = "         ";

	// PSP_METRICS_METHOD_BEGIN: FacesUtils
	/**
	 * Constructor
	 * */
	private FacesUtils() {}

	// PSP_METRICS_METHOD_END

	public static Object getSessionAttribute(String name) {
		return FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(name);
	}
	
	public static void setSessionAttribute(String name, Object value) {
		FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(name, value);
	}
	
	public static void removeSessionAttribute(String name) {
		FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(name);
	}

	public static String getRequestParameter(String name) {
		return (String) FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(name);
	}
	
	public static String getRequestAttribute(String name) {
		return (String) FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get(name);
	}
	
	public static void setRequestAttribute(String name, String value) {
		FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put(name, value);
	}
	
	public static void removeRequestAttribute(String name) {
		FacesContext.getCurrentInstance().getExternalContext().getRequestMap().remove(name);
	}

	// PSP_METRICS_METHOD_BEGIN: addInfoMessage
	/**
	 * Crea mensaje informativo
	 * 
	 * @param msg
	 *            , mensaje a mostrar
	 */
	public static void addInfoMessage(String msg, boolean global) {
		if (global) {
			FacesContext.getCurrentInstance().getExternalContext().getFlash().setKeepMessages(global);
		}
		addInfoMessage(null, msg);
	}

	// PSP_METRICS_METHOD_END

	// PSP_METRICS_METHOD_BEGIN: addErrorMessage
	/**
	 * Crea mensaje de error
	 * 
	 * @param msg
	 *            , mensaje a mostrar
	 */
	public static void addErrorMessage(String msg, boolean global) {
		if (global) {
			FacesContext.getCurrentInstance().getExternalContext().getFlash().setKeepMessages(global);
		}
		addErrorMessage(null, msg);
	}

	// PSP_METRICS_METHOD_END

	// PSP_METRICS_METHOD_BEGIN: addFatalMessage
	/**
	 * Crea mensaje de error fatal
	 * 
	 * @param msg
	 *            , mensaje a mostrar
	 */
	public static void addFatalMessage(String msg, boolean global) {
		if (global) {
			FacesContext.getCurrentInstance().getExternalContext().getFlash().setKeepMessages(global);
		}
		addFatalMessage(null, msg);
	}

	// PSP_METRICS_METHOD_END

	// PSP_METRICS_METHOD_BEGIN: addWarnMessage
	/**
	 * Crea mensaje de advertencia
	 * 
	 * @param msg
	 *            , mensaje a mostrar
	 */
	public static void addWarnMessage(String msg, boolean global) {
		if (global) {
			FacesContext.getCurrentInstance().getExternalContext().getFlash().setKeepMessages(global);
		}
		addWarnMessage(null, msg);
	}

	// PSP_METRICS_METHOD_END

	// PSP_METRICS_METHOD_BEGIN: addInfoMessage
	/**
	 * Crea mensaje informativo
	 * 
	 * @param clientId
	 * @param msg
	 *            , mensaje a mostrar
	 */
	public static void addInfoMessage(String clientId, String msg) {

		String mensaje = ESPACIO_BLANCO + msg;

		FacesContext.getCurrentInstance().addMessage(clientId,
				new FacesMessage(FacesMessage.SEVERITY_INFO, mensaje, mensaje));
	}

	// PSP_METRICS_METHOD_END

	// PSP_METRICS_METHOD_BEGIN: addErrorMessage
	/**
	 * Crea mensaje de error
	 * 
	 * @param clientId
	 * @param msg
	 *            , mensaje a mostrar
	 */
	public static void addErrorMessage(String clientId, String msg) {

		String mensaje = ESPACIO_BLANCO + msg;
		FacesContext.getCurrentInstance()
				.addMessage(
						clientId,
						new FacesMessage(FacesMessage.SEVERITY_ERROR, mensaje,
								mensaje));
	}

	// PSP_METRICS_METHOD_END

	// PSP_METRICS_METHOD_BEGIN: addFatalMessage
	/**
	 * Crea mensaje de error fatal
	 * 
	 * @param clientId
	 * @param msg
	 *            , mensaje a mostrar
	 */
	public static void addFatalMessage(String clientId, String msg) {

		String mensaje = ESPACIO_BLANCO + msg;
		FacesContext.getCurrentInstance()
				.addMessage(
						clientId,
						new FacesMessage(FacesMessage.SEVERITY_FATAL, mensaje,
								mensaje));
	}

	// PSP_METRICS_METHOD_END

	// PSP_METRICS_METHOD_BEGIN: addWarnMessage
	/**
	 * Crea mensaje de advertencia
	 * 
	 * @param clientId
	 * @param msg
	 *            , mensaje a mostrar
	 */
	public static void addWarnMessage(String clientId, String msg) {

		String mensaje = ESPACIO_BLANCO + msg;
		FacesContext.getCurrentInstance().addMessage(clientId,
				new FacesMessage(FacesMessage.SEVERITY_WARN, mensaje, mensaje));
	}

	// PSP_METRICS_METHOD_END

	// PSP_METRICS_METHOD_BEGIN: redirigir
	/**
	 * Redirige una aplicacion a la pantalla dirigida por una regla de
	 * navegacion
	 * 
	 * @param navigationRule
	 *            Regla de navegacion
	 */
	public static void redirigir(String navigationRule) {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		NavigationHandler navigationHandler = facesContext.getApplication()
				.getNavigationHandler();
		navigationHandler.handleNavigation(facesContext, null, navigationRule);
	}

	// PSP_METRICS_METHOD_END

	// PSP_METRICS_METHOD_BEGIN: quitarEspacios
	/**
	 * Quita espacios innecesarios en una cadena de caracteres.
	 * 
	 * @param cadena
	 *            Cadena a ser filtrada
	 * @return Cadena filtrada
	 */
	public static String quitarEspacios(String cadena) {

		String cadenaEditada = "";

		java.util.StringTokenizer tokens = new java.util.StringTokenizer(cadena);

		while (tokens.hasMoreTokens()) {
			cadenaEditada += " " + tokens.nextToken();
		}

		return cadenaEditada.trim();

	}

	// PSP_METRICS_METHOD_END

	// PSP_METRICS_METHOD_BEGIN: quitarTodosLosEspacios
	/**
	 * Quita todos los espacios en una cadena de caracteres.
	 * 
	 * @param cadena
	 *            Cadena a ser filtrada
	 * @return Cadena filtrada
	 */
	public static String quitarTodosLosEspacios(String cadena) {

		String cadenaEditada = "";

		java.util.StringTokenizer tokens = new java.util.StringTokenizer(cadena);

		while (tokens.hasMoreTokens()) {
			cadenaEditada += tokens.nextToken();
		}

		return cadenaEditada.trim();

	}

	// PSP_METRICS_METHOD_END

	// PSP_METRICS_METHOD_BEGIN: getMensaje
	/**
	 * Retorna un valor de una llave del archivo de propiedades
	 * 
	 * @param llave
	 *            Nombre de la llave
	 * @param etiquetas
	 *            Archivo de propiedades de origen. Nombre completo incluyendo
	 *            el paquete
	 * @return Valor de la llave. Cadena vacia si no encuentra la llave.
	 * @throws SifeapException
	 */
	public static String getMensaje(String etiquetas, String llave)
			throws SifeapException {
		try {
			FacesContext context = FacesContext.getCurrentInstance();
			Locale locale = context.getViewRoot().getLocale();
			ResourceBundle resourceBundleEnlaces = ResourceBundle.getBundle(
					etiquetas, locale);
			return resourceBundleEnlaces.getString(llave);
		} catch (MissingResourceException e) {
			throw new SifeapException(e);
		}
	}
	// PSP_METRICS_METHOD_END
	
	/**
	 * 
	 * @param input
	 * @param nombreArchivo
	 * @param adjunto
	 * @throws IOException
	 */
	public static void enviarAlNavegador(InputStream input, String nombreArchivo, boolean adjunto) throws IOException
    {
            FacesContext context = FacesContext.getCurrentInstance();
            ExternalContext externalContext = context.getExternalContext();
            
            String mimeType = externalContext.getMimeType(nombreArchivo);

            if (mimeType == null) {
            		//Tipo de archivo por defecto
                    mimeType = "application/octet-stream";
            }

            //Prepara el respose
            externalContext.setResponseBufferSize(10240);
            externalContext.setResponseContentType(mimeType);
            externalContext.setResponseHeader("Content-Disposition", String.format("%s;filename=\"%s\"",(adjunto ? "attachment" : "inline"), nombreArchivo));

            //Por Internet Explorer: http://support.microsoft.com/kb/316431
            if (((HttpServletRequest) externalContext.getRequest()).isSecure()) {
                    externalContext.setResponseHeader("Cache-Control", "public");
                    externalContext.setResponseHeader("Pragma", "public");
            }

            long size = stream(input, externalContext.getResponseOutputStream());
            externalContext.setResponseHeader("Content-Length", String.valueOf(size));

            context.responseComplete();
    }
	
	private static long stream(InputStream input, OutputStream output) throws IOException {
        ReadableByteChannel inputChannel = null;
        WritableByteChannel outputChannel = null;
        try {
                inputChannel = Channels.newChannel(input);
                outputChannel = Channels.newChannel(output);
                ByteBuffer buffer = ByteBuffer.allocateDirect(10240);
                long size = 0;
                while (inputChannel.read(buffer) != -1) {
                        buffer.flip();
                        size += outputChannel.write(buffer);
                        buffer.clear();
                }
                return size;
        } finally {
        	if (outputChannel != null) {
                try {
                	outputChannel.close();
                }
                catch (IOException e) {}
        	}

        	if (inputChannel != null) {
                try {
                	inputChannel.close();
                }
                catch (IOException e) {}
        	}
        }
	}
}